﻿using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Primitives;
using Service.Core.Identity.Model;
using Service.Core.Redis.Services;

namespace Service.Core.Identity.Handler
{
    /// <summary>
    /// 内部调用授权处理器 继承AuthorizationHandler ，并且需要一个权限必要参数
    /// </summary>
    public class InnerHandler : AuthorizationHandler<InnerRequirement>
    {
        private readonly IHttpContextAccessor httpContextAccessor;
        private readonly IRedisService _redisService;

        /// <summary>
        /// 验证方案提供对象
        /// </summary>
        public IAuthenticationSchemeProvider Schemes { get; set; }


        /// <summary>
        /// 构造函数注入
        /// </summary>
        /// <param name="schemes"></param>
        /// <param name="httpContextAccessor"></param>
        /// <param name="modulePermissionService"></param>
        /// <param name="tenantService"></param>
        /// <param name="sysUserSession"></param>
        public InnerHandler(IAuthenticationSchemeProvider schemes,
            IHttpContextAccessor httpContextAccessor,
            IRedisService redisService)
        {
            Schemes = schemes;
            this.httpContextAccessor = httpContextAccessor;
            _redisService = redisService;
        }

        /// <summary>
        /// 重写异步处理程序
        /// </summary>
        /// <param name="context"></param>
        /// <param name="requirement"></param>
        protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context,
            InnerRequirement requirement)
        {
            var httpContext = httpContextAccessor.HttpContext;
            if (httpContext != null)
            {
                //从AuthorizationHandlerContext转成HttpContext，以便取出表头信息
                //请求Url
                var questUrl = httpContext.Request.Path.Value?.ToLower();
                // 整体结构类似认证中间件UseAuthentication的逻辑，具体查看开源地址
                // https://github.com/dotnet/aspnetcore/blob/master/src/Security/Authentication/Core/src/AuthenticationMiddleware.cs
                httpContext.Features.Set<IAuthenticationFeature>(new AuthenticationFeature
                {
                    OriginalPath = httpContext.Request.Path,
                    OriginalPathBase = httpContext.Request.PathBase
                });

                //判断请求是否停止
                var handlers = httpContext.RequestServices.GetRequiredService<IAuthenticationHandlerProvider>();
                foreach (var scheme in await Schemes.GetRequestHandlerSchemesAsync())
                {
                    var handler =
                        await handlers.GetHandlerAsync(httpContext, scheme.Name) as IAuthenticationRequestHandler;
                    if (handler != null && await handler.HandleRequestAsync())
                    {
                        context.Fail();
                        return;
                    }
                }
                if (!httpContext.Request.Headers.TryGetValue("InnerSecretKey", out StringValues values))
                {
                    context.Fail();
                    return;
                }
                if (values.Contains(DefaultInnerKeys.InnerKeys))
                {
                    context.Succeed(requirement);
                    return;
                }
                context.Fail();
                return;
            }
        }
    }
}